(define-module (shuffling)
  #:export (fisher-yates-shuffle)
  #:use-module (rnrs base)
  #:use-module ((guile) #:select (lambda* λ record-constructor))
  #:use-module ((random-number-generator) #:select (make-random-integer-generator))
  #:pure)


(define fisher-yates-shuffle
  (lambda* (lst #:key (rng (make-random-integer-generator #:seed 12345)))
    "Shuffle the given list LST using the optional keyword argument
provided random number generator RNG. If no random number generator is
given, a predetermined one will be used."
    (let ([lst-as-vec (list->vector lst)])
      (let loop ([result '()]
                 [elements-to-pick (vector-length lst-as-vec)])
        (cond
         [(zero? elements-to-pick) result]
         [else
          (let* ([rand-int (rng elements-to-pick)]
                 [val (vector-ref lst-as-vec rand-int)])
            (vector-set! lst-as-vec
                         rand-int
                         (vector-ref lst-as-vec
                                     (- elements-to-pick 1)))
            (loop
             (cons val result)
             (- elements-to-pick 1)))])))))
